﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.IO;
using System.Data.Services;
using VsxFactory.Modeling.Repository;
using System.Data.Services.Providers;
using VsxFactory.Modeling.Strategies;

namespace VsxFactory.Repository.StrategiesGallery
{
    // http://blogs.msdn.com/b/astoriateam/archive/2010/08/04/data-services-streaming-provider-series-implementing-a-streaming-provider-part-1.aspx
    class PackageStreamProvider : LocalPackageRepository, IDataServiceStreamProvider
    {
        private const string contentType = "application/octet-stream";

        public PackageStreamProvider(Strategies dataService, StrategyDataContext dataSource) : base(new ServerStrategyContext(), VsxFactory.Modeling.Repository.PackageKind.Strategy)
        {
        }

        #region IDataServiceStreamProvider Members

        public void DeleteStream(object entity, DataServiceOperationContext operationContext)
        {
            // Suppression d'un package
            var entry = entity as PackageInfo;
            if (entry == null)
            {
                throw new DataServiceException(500, "Internal Server Error");
            }

            Uninstall(entry);
        }

        public Stream GetReadStream(object entity, string etag, bool? checkETagForEquality, DataServiceOperationContext operationContext)
        {
            if (checkETagForEquality != null)
            {
                // This implementation does not support eTag associated with BLOBs
                throw new DataServiceException(400, "This server does not support eTags.");
            }

            var entry = entity as PackageInfo;
            if (entry == null)
            {
                throw new DataServiceException(500, "Internal Server Error");
            }

            try
            {
                // Execute the query and return a stream that contains the image bytes.
                return new FileStream(Context.Settings.ResolvePackageFileName(entry), FileMode.Open, FileAccess.Read, FileShare.Read);
            }
            catch (Exception ex)
            {
                throw new DataServiceException(500, string.Format("A binary stream could not be returned for the package with an identity of {0} : {1}", entry.ID, ex.Message));
            }
        }

        public Uri GetReadStreamUri(object entity, DataServiceOperationContext operationContext)
        {
            // Allow the runtime set the URI of the Media Resource.
            return null;
        }

        public string GetStreamContentType(object entity, DataServiceOperationContext operationContext)
        {
            return contentType;
        }

        public string GetStreamETag(object entity, DataServiceOperationContext operationContext)
        {
            return null;
        }

        public Stream GetWriteStream(object entity, string etag, bool? checkETagForEquality, DataServiceOperationContext operationContext)
        {
            if (checkETagForEquality != null)
            {
                // this stream provider implementation does not support ETags associated with BLOBs
                throw new DataServiceException(400, "This server does not support ETags associated with BLOBs");
            }

            var currentPackage = entity as PackageInfo;
            if (currentPackage == null)
            {
                throw new DataServiceException(500, "Internal Server Error: the Media Link Entry could not be determined.");
            }

            if (operationContext.RequestMethod == "POST")
            {
                var p = PackageInfo.CreateFromSlug(operationContext.RequestHeaders["Slug"]);
                currentPackage.Name = p.Name;
                currentPackage.Version = p.Version;
                currentPackage.Kind = p.Kind;
                currentPackage.Description = "$temp$";
                currentPackage.RepositorySource = String.Empty;
            }
            var fn = Context.Settings.ResolvePackageFileName(currentPackage);
            Directory.CreateDirectory(Path.GetDirectoryName(fn));
            return new FileStream(fn, FileMode.Create, FileAccess.ReadWrite);
        }

        public string ResolveType(string entitySetName, DataServiceOperationContext operationContext)
        {
            // We should only be handling Employee types.
            if (entitySetName == "Packages")
            {
                return typeof(PackageInfo).FullName;
            }
            else
            {
                // This will raise an DataServiceException.
                return null;
            }
        }

        public int StreamBufferSize
        {
            // Use a buffer size of 64K bytes.
            get { return 64000; }
        }
        #endregion
    }

}